#include "audioresample.h"
#include <QDebug>
#include <QFile>

extern "C" {

    #include <libswresample/swresample.h>
    #include <libavutil/avutil.h>
}


#define ERROR_BUF(ret) \
        char err_buffer[1024]; \
        av_strerror(swr_init_res,err_buffer,sizeof(err_buffer));


AudioResample::AudioResample(QObject *parent) : QThread(parent)
{

    connect(this,&QThread::finished,this,&QThread::deleteLater);

}

AudioResample::~AudioResample()
{

    disconnect();

    requestInterruption();

    quit();

    wait();

    qDebug() << "audioResample destroy";
}




void AudioResample::resample()
{

//    qDebug() << "resample";

    const char* inPMCPath = "/Users/tgy/Documents/ffmpeg/audio/recode_pcm_1618500714.pcm";
    const char* outPMCPath = "/Users/tgy/Documents/ffmpeg/audio/recode_pcm_44800_1_16.pcm";

    AVSampleFormat inSampleFormat = AV_SAMPLE_FMT_FLT;
    int inSampleRate = 44100;
    int inChannelLayout = AV_CH_LAYOUT_STEREO;
    int inNumChannel = av_get_channel_layout_nb_channels(inChannelLayout);
    int inBytesPerSample = inNumChannel * av_get_bytes_per_sample(inSampleFormat);


    AVSampleFormat outSampleFormat = AV_SAMPLE_FMT_S16;
    int outSampleRate = 44800;
    int outChannelLayout = AV_CH_LAYOUT_MONO;
    int outNumChannel = av_get_channel_layout_nb_channels(outChannelLayout);
    int outBytesSample = outNumChannel * av_get_bytes_per_sample(outSampleFormat);

    /**
     * @brief swr_alloc_set_opts
     *
     * struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
                                      int log_offset, void *log_ctx);
     */
    SwrContext* swrContext =swr_alloc_set_opts(nullptr,
                                               outChannelLayout,outSampleFormat,outSampleRate,
                                               inChannelLayout,inSampleFormat,inSampleRate,
                                               0,
                                               nullptr
                                               );
    if(swrContext == nullptr) {

        qDebug() << "swr_alloc_set_opts fail";
        return;
    }

    int swr_init_res = swr_init(swrContext);

    if(swr_init_res < 0) {


        char buffer[1024];
        av_strerror(swr_init_res,buffer,sizeof(buffer));
        qDebug() << "swr_init fail message:" << buffer;

        swr_free(&swrContext);
        return;
    }

    // 创建输入缓冲区
    /**

int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
                                       int nb_samples, enum AVSampleFormat sample_fmt, int align);
     */

    uint8_t** inAudioData = nullptr;
    int inLinesize = 0;
    int inSamples = 1024;
    int in_array_samples = av_samples_alloc_array_and_samples(&inAudioData,
                                       &inLinesize,
                                       inNumChannel,
                                       inSamples,
                                       inSampleFormat,
                                       1);
    if(in_array_samples < 0) {

        ERROR_BUF(in_array_samples)
        qDebug() << "av_samples_alloc_array_and_samples " << err_buffer;


        swr_free(&swrContext);
        return;
    }

    // 创建输入缓冲区
    /**

int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
                                       int nb_samples, enum AVSampleFormat sample_fmt, int align);
     */

    uint8_t** outAudioData = nullptr;
    int outLinesize = 0;
    int outSamples = 1024;
    int out_array_samples = av_samples_alloc_array_and_samples(&outAudioData,
                                       &outLinesize,
                                       outNumChannel,
                                       outSamples,
                                       outSampleFormat,
                                       1);
    if(out_array_samples < 0) {

        ERROR_BUF(out_array_samples)
        qDebug() << "av_samples_alloc_array_and_samples " << err_buffer;

        av_freep(&inAudioData);
        swr_free(&swrContext);
        return;
    }

    QFile inFile(inPMCPath);

    if(!inFile.open(QFile::ReadOnly)) {


        qDebug() << "inPCMPath open fail";

        av_freep(&inAudioData);
        av_freep(&outAudioData);
        swr_free(&swrContext);
        return;
    }

    QFile outFile(outPMCPath);

    if(!outFile.open(QFile::WriteOnly)) {


        qDebug() << "outPMCPath open fail";

        inFile.close();
        av_freep(&inAudioData);
        av_freep(&outAudioData);
        swr_free(&swrContext);
        return;
    }

    int len = 0;
    while ((len = inFile.read((char*)inAudioData[0],inLinesize)) > 0) {

        inSamples = len / inBytesPerSample;

        // 重采样的样本数
        int convert_res = swr_convert(swrContext,outAudioData,outSamples,(const uint8_t**)inAudioData,inSamples);

        if(convert_res < 0) {

            ERROR_BUF(convert_res);
            qDebug() << "swr_convert fail " << err_buffer;
            break;
        }

        outFile.write((char*)outAudioData[0],convert_res * outBytesSample);
    }


    inFile.close();
    outFile.close();

    av_freep(&inAudioData);
    av_freep(&outAudioData);
    swr_free(&swrContext);
}

void AudioResample::run()
{

    resample();
}
